package com.yoj.judgeservice.listener;

import com.yoj.common.common.ResultCodeEnum;
import com.yoj.common.constant.MqConstant;
import com.yoj.common.exception.BusinessException;
import com.yoj.judgeservice.service.JudgeService;
import com.yoj.model.entity.QuestionSubmit;
import com.yoj.model.enums.QuestionSubmitStatusEnum;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * 消息队列消费者
 */
@Component
@Slf4j
public class RabbitMqListener {

    @Resource
    private JudgeService judgeService;

    // 指定程序监听的消息队列和确认机制
    @SneakyThrows
    @RabbitListener(queues = {MqConstant.JUDGE_QUEUE_NAME}, ackMode = "MANUAL")
    public void receiveMessage(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
        log.info("判题服务从消息队列中获取题目提交ID：{}，执行判题", message);
        if (StringUtils.isBlank(message) || message.equals("null")) {
            // 消息为空，则拒绝消息（不重试），进入死信队列
            channel.basicNack(deliveryTag, false, false);
            throw new BusinessException(ResultCodeEnum.OPERATION_ERROR, "消息为空");
        }
        try {
            // 执行判题
            QuestionSubmit questionSubmit = judgeService.doJudge(Long.parseLong(message));
            log.info("消息队列判题结果：{}", questionSubmit);
            // 判题失败进入死信队列
            if (!QuestionSubmitStatusEnum.SUCCESS.getValue().equals(questionSubmit.getStatus())) {
                channel.basicNack(deliveryTag, false, false);
            } else {
                // 手动确认消息
                channel.basicAck(deliveryTag, false);
            }
        } catch (Exception e) {
            log.error("处理消息时发生异常：{}", e.getMessage(), e);
            channel.basicNack(deliveryTag, false, false);
            throw new BusinessException(ResultCodeEnum.OPERATION_ERROR, e.getMessage());
        }
    }
}
